package es.uca.plii.warrenl0;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/***
 * Implementación concreta de un nodo tipo variable. Mantiene una lista de todas
 * las variables que se han descubierto para que cuando se encuentre una repetida
 * se devuelva una referencia a la ya existente
 * @author Rafael Sánchez, Alfonso Sendra
 */
public class NodoVariable extends NodoImpl {

    private static List<NodoVariable> listaVariables = new ArrayList<NodoVariable>();

    /**
     * Limpia la lista de variables
     */
    public static void limpiaListaVariables() {
        listaVariables.clear();
    }

    /**
     * Factoría para la creación de un nodo tipo variable. Lo crea si no existe
     * y devuelve la referencia si ya existe
     * @param nombre el nombre de la variable
     * @return el nodo variable
     */
    public static NodoVariable getInstance(String nombre) {
        int localizacion = listaVariables.indexOf(new NodoVariable(nombre));

        if (localizacion == -1) {
            NodoVariable nuevaVariable = new NodoVariable(nombre);
            listaVariables.add(nuevaVariable);
            return nuevaVariable;
        } else {
            return listaVariables.get(localizacion);
        }
    }
    private String nombre;

    /**
     * Devuelve el nombre de la variable
     * @return el nombre de la variable
     */
    public String getNombre() {
        return nombre;
    }

    /**
     * Establece el nombre de la variable
     * @param nombre el nombre de la variable
     */
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    /**
     * @param nombre nombre de la variable
     */
    private NodoVariable(String nombre) {
        this.nombre = nombre;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final NodoVariable other = (NodoVariable) obj;
        if ((this.nombre == null) ? (other.nombre != null) : !this.nombre.equals(other.nombre)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 83 * hash + (this.nombre != null ? this.nombre.hashCode() : 0);
        return hash;
    }

    /**
     * Devuelve el tipo de nodo concreto que se está implementando
     * @return Nodo.NODOVARIABLE
     */
    public int getTipo() {
        return Nodo.NODOVARIABLE;
    }

    /**
     * Implementa el método numerar profundidades llamando al método
     * anadirNodoAlMapa del objeto proporcionado que implementa el interfaz
     * ExtractorProfundidades.
     *
     * @param profundidad Profundidad del nodo padre. Cero cuando se llama al
     * método desde el nodo raíz.
     * @param ep Objeto que implementa el interfaz. que va a is creando el mapa
     * de profundidades.
     */
    public void numerarProfundidades(int profundidad,ExtractorProfundidades ep) {
       profundidad++;
       ep.anadirNodoAlMapa(Integer.valueOf(profundidad), this);
    }


    /**
     * Formato "flattened" de la variable, llamado desde cualquiera de las 
     * versiones de obtenerFlattenedForms, obtenerTokenizedForms, u 
     * obtenerInstructions de NodoEstructura 
     * @return El nombre de la variable
     */
    public String flattenedForm() {
        return this.nombre;
    }

    /**
     * No realiza ninguna operación
     * @param flt
     */
    public void obtenerFlattenedForms(Map<Integer, String> flt) {
       // No hace nada
    }

    /**
     * No realiza ninguna operación
     * @param flt
     */
    public void obtenerTokenizedForms(Map<Integer, String> flt) {
       // No hace nada
    }

    /**
     * No realiza ninguna operación
     * @param flt
     */
    public void obtenerInstructions(Map<Integer, CompInstruccion> flt) {
        //No hace nada
    }


}
